home *** CD-ROM | disk | FTP | other *** search
- #include <math.h>
- #include "point3.h"
- #include "transform.h"
- #include "ooglutil.h"
- #include "polyint.h"
-
- static char msg[] = "polyint.c";
-
- #define FUDGE 1.e-6
-
- #define PT3SUB_XY(a, b, dst) { (dst).x = (a).x - (b).x; \
- (dst).y = (a).y - (b).y; \
- (dst).z = 0.0; }
- #define PT3LENGTH_XY(a) sqrt((a).x*(a).x + (a).y*(a).y)
- #define PT3DOT_XY(a, b) ((a).x*(b).x + (a).y*(b).y)
-
- /*
- * Internal routines. These should not need to be called directly.
- */
- static int PolyInt_InBBox(int n_verts, Point3 *verts, float tol);
- static float PolyInt_Angle(Point3 *pt1, Point3 *pt2);
- static int PolyInt_Origin(int n_verts, Point3 *verts, Point3 *origin);
-
- int PolyZInt(int n_verts, Point3 *verts, float tol,
- vvec *ip, vvec *vertices, vvec *edges, vvec *ep)
- {
- int i, j, flag;
- int n_oldhits, n_hits = 0;
-
- Point3 v1, v2, pt, bma;
- float d, t, len, f;
-
- float angsum = 0.0;
-
- /* Do test for trivial rejection */
- if (!PolyInt_InBBox(n_verts, verts, tol)) return 0;
-
- n_hits = n_oldhits = VVCOUNT(*ip);
-
- /* Go through the edges of the polygon looking for edge and vertex hits. */
- for (i = 0; i < n_verts; i++) {
- j = (i + 1) % n_verts;
-
- Pt3From(&v1, (float)verts[i].x, (float)verts[i].y, (float)0.0);
- Pt3From(&v2, (float)verts[j].x, (float)verts[j].y, (float)0.0);
-
- Pt3Sub(&verts[j], &verts[i], &bma);
- len = PT3LENGTH_XY(bma);
- t = - PT3DOT_XY(verts[i], bma) / len;
-
- f = t / len;
- Pt3From(&pt, (float)(verts[i].x + f * bma.x),
- (float)(verts[i].y + f * bma.y), (float)(verts[i].z + f * bma.z));
- d = PT3LENGTH_XY(pt);
-
- if (d < tol && t > -tol) {
- if (t < tol) {
- *VVINDEX(*vertices, int, n_hits) = i;
- *VVINDEX(*edges, int, n_hits) = -1;
- *VVINDEX(*ip, Point3, n_hits) = verts[i];
- n_hits++;
- } else if (t < len - tol) {
- *VVINDEX(*ip, Point3, n_hits) = pt;
- *VVINDEX(*vertices, int, n_hits) = -1;
- *VVINDEX(*edges, int, n_hits) = i;
- *VVINDEX(*ep, Point3, n_hits) = pt;
- n_hits++;
- }
- }
-
- angsum += PolyInt_Angle(&v1, &v2);
-
- }
-
- /* Look for the face hits */
- if (!(n_hits - n_oldhits) && n_verts > 2 && fabs(angsum / M_2_PI) > 0.5
- && PolyInt_Origin(n_verts, verts, &pt)) {
- *VVINDEX(*ip, Point3, n_hits) = pt;
- *VVINDEX(*vertices, int, n_hits) = -1;
- *VVINDEX(*edges, int, n_hits) = -1;
- n_hits++;
- }
-
- VVCOUNT(*ip) = n_hits;
- VVCOUNT(*vertices) = n_hits;
- VVCOUNT(*edges) = n_hits;
-
- return(n_hits - n_oldhits);
-
- }
-
-
- int PolyNearPosZInt(int n_verts, Point3 *verts, float tol,
- Point3 *ip, int *vertex, int *edge, Point3 *ep) {
- int i, closest;
- vvec v_ip, v_vertices, v_edges, v_ep;
- float zmax;
-
- VVINIT(v_ip, Point3, 4);
- VVINIT(v_vertices, int, 4);
- VVINIT(v_edges, int, 4);
- VVINIT(v_ep, Point3, 4);
-
- closest = -1;
-
- if (!PolyZInt(n_verts, verts, tol, &v_ip, &v_vertices, &v_edges, &v_ep))
- return 0;
-
- for (i = 0; i < VVCOUNT(v_ip); i++)
- if (VVINDEX(v_ip, Point3, i)->z > -1.0 &&
- (closest == -1 || VVINDEX(v_ip, Point3, i)->z > zmax)) {
- closest = i;
- zmax = VVINDEX(v_ip, Point3, i)->z;
- }
-
- if (closest >= 0) {
- Pt3Copy(VVINDEX(v_ip, Point3, closest), ip);
- *vertex = *VVINDEX(v_vertices, int, closest);
- *edge = *VVINDEX(v_edges, int, closest);
- Pt3Copy(VVINDEX(v_ep, Point3, closest), ep);
- }
-
- vvfree(&v_ip);
- vvfree(&v_vertices);
- vvfree(&v_edges);
- vvfree(&v_ep);
-
- return ((closest < 0) ? 0 : 1);
- }
-
-
- int PolyLineInt(Point3 *pt1, Point3 *pt2, int n_verts, Point3 *verts,
- float tol, vvec *ip, vvec *vertices, vvec *edges, vvec *ep)
- {
- int i;
- int n_hits, old_n_hits;
- Point3 *vertcopy;
- Transform T, Tinv;
-
- PolyInt_Align(pt1, pt2, T);
- TmInvert(T, Tinv);
-
- vertcopy = OOGLNewNE(Point3, n_verts, msg);
- for (i = 0; i < n_verts; i++) Pt3Transform(T, &verts[i], &vertcopy[i]);
-
- old_n_hits = VVCOUNT(*ip);
- n_hits = PolyZInt(n_verts, vertcopy, tol, ip, vertices, edges, ep);
- for (i = 0; i < n_hits; i++) {
- Pt3Transform(Tinv, VVINDEX(*ip, Point3, old_n_hits + i),
- VVINDEX(*ip, Point3, old_n_hits + i));
- Pt3Transform(Tinv, VVINDEX(*ep, Point3, old_n_hits + i),
- VVINDEX(*ep, Point3, old_n_hits + i));
- }
-
- OOGLFree(vertcopy);
-
- return n_hits;
-
- }
-
-
- int PolyRayInt(Point3 *pt1, Point3 *pt2, int n_verts, Point3 *verts,
- float tol, vvec *ip, vvec *vertices, vvec *edges, vvec *ep)
- {
- int i, j;
- int n_hits, old_n_hits;
- Point3 *vertcopy;
- Transform T, Tinv;
-
- PolyInt_Align(pt1, pt2, T);
- TmInvert(T, Tinv);
-
- vertcopy = OOGLNewNE(Point3, n_verts, msg);
- for (i = 0; i < n_verts; i++) Pt3Transform(T, &verts[i], &vertcopy[i]);
-
- old_n_hits = VVCOUNT(*ip);
- n_hits = PolyZInt(n_verts, vertcopy, tol, ip, vertices, edges, ep);
- for (i = j = 0; i < n_hits; i++)
- if (VVINDEX(*ip, Point3, old_n_hits + i)->z <= 0) {
- Pt3Transform(Tinv, VVINDEX(*ip, Point3, old_n_hits + i),
- VVINDEX(*ip, Point3, old_n_hits + j));
- Pt3Transform(Tinv, VVINDEX(*ep, Point3, old_n_hits + i),
- VVINDEX(*ep, Point3, old_n_hits + j));
- j++;
- }
-
- OOGLFree(vertcopy);
-
- return j;
-
- }
-
-
- int PolySegmentInt(Point3 *pt1, Point3 *pt2, int n_verts, Point3 *verts,
- float tol, vvec *ip, vvec *vertices, vvec *edges, vvec *ep)
- {
- int i, j;
- int n_hits, old_n_hits;
- Point3 *vertcopy;
- Transform T, Tinv;
-
- PolyInt_Align(pt1, pt2, T);
- TmInvert(T, Tinv);
-
- vertcopy = OOGLNewNE(Point3, n_verts, msg);
- for (i = 0; i < n_verts; i++) Pt3Transform(T, &verts[i], &vertcopy[i]);
-
- old_n_hits = VVCOUNT(*ip);
- n_hits = PolyZInt(n_verts, vertcopy, tol, ip, vertices, edges, ep);
- for (i = j = 0; i < n_hits; i++)
- if ((VVINDEX(*ip, Point3, old_n_hits + i)->z <= 0) &&
- (VVINDEX(*ip, Point3, old_n_hits + i)->z >= -1.0)) {
- Pt3Transform(Tinv, VVINDEX(*ip, Point3, old_n_hits + i),
- VVINDEX(*ip, Point3, old_n_hits + j));
- Pt3Transform(Tinv, VVINDEX(*ep, Point3, old_n_hits + i),
- VVINDEX(*ep, Point3, old_n_hits + j));
- j++;
- }
-
- OOGLFree(vertcopy);
-
- VVCOUNT(*ip) = old_n_hits + j;
- vvtrim(ip);
-
- return j;
-
- }
-
-
- void PolyInt_Align(Point3 *pt1, Point3 *pt2, Transform T) {
- Point3 newpt2;
- Transform Ttmp;
-
- if (!bcmp(pt1, pt2, sizeof(Point3))) {
- OOGLError(1, "PolyInt_Align called with identical points.");
- TmIdentity(T);
- return;
- }
-
- TmTranslate(T, -pt1->x, -pt1->y, -pt1->z);
- Pt3Transform(T, pt2, &newpt2);
-
- TmRotateY(Ttmp, -atan2(newpt2.x, -newpt2.z));
- TmConcat(T, Ttmp, T);
- Pt3Transform(T, pt2, &newpt2);
-
- TmRotateX(Ttmp, -atan2(newpt2.y, -newpt2.z));
- TmConcat(T, Ttmp, T);
- Pt3Transform(T, pt2, &newpt2);
-
- if (newpt2.z == 0.0) {
- OOGLError(1, "Second point too close to first point in PolyInt_Align");
- TmIdentity(T);
- return;
- }
- TmScale(Ttmp, -1.0 / newpt2.z, -1.0 / newpt2.z, -1.0 / newpt2.z);
- TmConcat(T, Ttmp, T);
-
- }
-
- /*
- * PolyInt_InBBox
- * Returns non-zero if the origin is inside the polygon described by
- * verts or within tol of begin so; returns 0 otherwise.
- */
- static int PolyInt_InBBox(int n_verts, Point3 *verts, float tol) {
- int i;
- int posx = 0, negx = 0, posy = 0, negy = 0;
-
- for (i = 0; i < n_verts; i++, verts++) {
- if (verts->x < tol) negx |= 1;
- if (verts->x > -tol) posx |= 1;
- if (verts->y < tol) negy |= 1;
- if (verts->y > -tol) posy |= 1;
- }
-
- return (posx & negx & posy & negy);
-
- }
-
-
- static float PolyInt_Angle(Point3 *pt1, Point3 *pt2) {
- float ans;
-
- if (Pt3Distance(pt1, pt2) < FUDGE) return 0;
- ans = PT3DOT_XY(*pt1, *pt2) /
- sqrt((double)(PT3DOT_XY(*pt1, *pt1) * PT3DOT_XY(*pt2, *pt2)));
- ans = acos(ans);
- return(ans * ((pt1->x * pt2->y - pt1->y * pt2->x) >= 0 ? 1.0 : -1.0));
-
- }
-
-
- static int PolyInt_Origin(int n_verts, Point3 *verts, Point3 *origin) {
- int bi, ci;
- float pz, pw;
-
- /* Find the first vertex different from the 0th vertex */
- for (bi = 0; bi < n_verts && !bcmp(&verts[0], &verts[bi], sizeof(Point3));
- bi++);
- if (bi >= n_verts) {
- Pt3Copy(&verts[0], origin);
- return 0;
- }
-
- /* Find the first vertex not collinear with the other two vertices */
- for (ci = bi+1; ci < n_verts; ci++) {
- pz = (verts[0].x * (verts[bi].y - verts[ci].y)
- - verts[0].y * (verts[bi].x - verts[ci].x)
- + (verts[bi].x * verts[ci].y - verts[bi].y * verts[ci].x));
- if (fabs(pz) > FUDGE) break;
- }
- if (ci >= n_verts) {
- Pt3Copy(&verts[0], origin);
- return 0;
- }
-
- pw = (verts[0].x * (verts[bi].z*verts[ci].y - verts[bi].y*verts[ci].z)
- - verts[0].y * (verts[bi].z*verts[ci].x - verts[bi].x*verts[ci].z)
- + verts[0].z * (verts[bi].y*verts[ci].x - verts[bi].x*verts[ci].y));
-
- origin->x = origin->y = 0.0;
- origin->z = -pw / pz;
-
- return 1;
- }
-
-
-
-
-
-